package com.lam.framework.operLog.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.lam.common.utils.CollectionUtil;
import com.lam.framework.operLog.handlers.LogHandler;
import com.lam.framework.operLog.model.OperateLog;
import com.lam.framework.security.GlobalExceptionHandler;

/**
 * 操作日志记录处理
 * 
 * @author lam
 */
@Order(1)
@Aspect
@Component
public class LogAspect {

//	private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

	// 配置织入点
	@Pointcut("execution(* com.lam..*.controller..*.*(..)) &&@annotation(com.lam.framework.operLog.annotation.Log)")
	public void logPointCut() {}

    @Around("logPointCut()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    	
    	OperateLog operLog = null;
		Class<?> handlerClass = joinPoint.getTarget().getClass();
		Object result;
		long startTime = System.currentTimeMillis();
		try {
			Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
			operLog = LogHandler.collectReqLog(handlerClass, method, joinPoint.getArgs());
			LogHandler.printReqParam(operLog, handlerClass);
			
			result = joinPoint.proceed(injectLogObject(joinPoint.getArgs(), method, operLog));
			handleResult(operLog, result, startTime, handlerClass, null);
		} catch (Throwable e) {
			handleResult(operLog, GlobalExceptionHandler.wrapResult(e), startTime, handlerClass, e);
			throw e;
		}
		return result;
	}
    
    private Object[] injectLogObject(Object[] args, Method method, OperateLog operLog) {
    	Class<?>[] types = method.getParameterTypes();
    	if(operLog == null || CollectionUtil.isEmpty(args) || CollectionUtil.isEmpty(types)) {
    		return args;
    	}
    	int logIndex = -1;
    	for (int i = 0; i < types.length; i++) {
			if(types[i] == OperateLog.class) {
				logIndex = i;
				break;
			}
		}
    	if(logIndex>=0) {
    		args[logIndex] = operLog;
    	}
    	return args;
    }
    
    private void handleResult(OperateLog operLog, Object result, long startTime, Class<?> handlerClass, Throwable e) {
    	operLog.setElTime(System.currentTimeMillis() - startTime);
    	LogHandler.collectResLog(operLog, result, e);
		LogHandler.printResResult(operLog, handlerClass);
		LogHandler.submitLog(operLog);
    }
	
}
